{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# SparK: Visualization for \"mask pattern vanishing\" issue\n",
    "Load binary images and visualize the convoluted images."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "# load images\n",
    "\n",
    "import torch\n",
    "from torchvision.io import read_image\n",
    "\n",
    "N = 3\n",
    "raw_inp = []\n",
    "for i in range(1, N+1):\n",
    "    chw = read_image(f'viz_imgs/spconv{i}.png')[:1] # only take the first channel\n",
    "    BLACK = 0\n",
    "    # binarize: black represents active (1), white represents masked (0)\n",
    "    active = torch.where(chw == BLACK, torch.ones_like(chw, dtype=torch.float) * 255., torch.zeros_like(chw, dtype=torch.float))\n",
    "    raw_inp.append(active)\n",
    "raw_inp = torch.stack(raw_inp, dim=0)\n",
    "active = raw_inp.bool()     # active: 1, masked: 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "# apply dense conv and sparse conv\n",
    "\n",
    "import encoder\n",
    "dense_conv = torch.nn.Conv2d(1, 1, kernel_size=(3, 3), stride=1, padding=1, bias=False)\n",
    "sparse_conv = encoder.SparseConv2d(1, 1, kernel_size=(3, 3), stride=1, padding=1, bias=False)\n",
    "\n",
    "dense_conv.weight.data.fill_(1/dense_conv.weight.numel()), dense_conv.weight.requires_grad_(False)\n",
    "sparse_conv.weight.data.fill_(1/sparse_conv.weight.numel()), sparse_conv.weight.requires_grad_(False)\n",
    "\n",
    "# after the first dense conv\n",
    "conv1 = (dense_conv(raw_inp) > 0) * 255.    # binarize\n",
    "# after the second dense conv\n",
    "conv2 = (dense_conv(conv1) > 0) * 255.      # binarize\n",
    "\n",
    "# after the sparse conv\n",
    "encoder._cur_active = active\n",
    "spconv = (sparse_conv(raw_inp) > 0) * 255.  # binarize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA7YAAAL+CAYAAACZhogtAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA/6klEQVR4nO3deZhcVZ0//k93OktDNghLFkKCgAIhYMKaECDbMPAAsukADmtQkcUFle/DgI+II6KMjjIoLixRMDiOZAaHMcmwJcqACISQBAgKIZAYyQaYANnT9/cHv5R9e63eUnW6X6/n6edJVc49depW3VvnfZdzKrIsywIAAAASVVnqBgAAAEBbCLYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkVZW6AZTenDlzYsKECYXHs2fPjvHjx5euQQBAu8qyLBYvXhwvvPBCLFu2LNatWxe9evWKAQMGxMiRI+PQQw+Nbt26lbqZAK0m2AIAdEJr166N+++/P37zm9/E7NmzY82aNY2W7du3b1x44YXxhS98IYYPH77jGgnQTlyKDECjli1bFtOnT49rrrkmJk6cGP369YuKiorC31e/+tVSNxFowOzZs2OPPfaIiy66KH71q181GWojItatWxe33nprjBw5MqZOnbqDWgnQfpyxBSBnw4YNcfbZZ8fTTz8dK1asKHVzgFZYu3ZtbN68Ofdcz54946ijjooDDjgg9thjj9i0aVM8//zzMXv27Ni4cWNERLz77rsxZcqU2LBhQ1x++eWlaDpAqwi2xPjx4yPLslI3AygTmzZtigceeKDUzQDaQUVFRUyaNCkuvfTSOOWUU6JXr171yqxYsSI+85nPxH333Vd47jOf+Uwcc8wxceihh+7I5gK0mkuRASjK0KFD4+ijjy51M4AiVFRUxEknnRTz5s2Lhx56KD760Y82GGojIgYOHBj/8R//Eeeee27huZqamrj22mt3VHMB2qwic6oOgFr++te/xgc/+ME44ogj4ogjjojDDz88jjjiiNhzzz3rjaJ+/fXXu88WytDWrVujqqplF+a99dZbMXz48HjnnXciIqJ79+6xZs2a6Nu3b0c0EaBduRQZgJz+/fvHqlWrSt0MoA1aGmojInbdddc44YQTYvr06RERsWXLlpg3b14cf/zx7d08gHaXdLD905/+FPPnz4833ngj3n333Rg+fHh8/OMfb7Ds6tWr4/nnn49XXnkl3n777di2bVvssssuMXjw4BgzZkzsvvvuO7j1ndO8efPihRdeiOXLl0evXr1i6NChMX78+Nh1113bpf6VK1fGE088EcuXL4/169fHoEGD4sgjj4wPfehD7VI/ADveW2+9FU888US88cYb8eabb0ZlZWUMGDAgDjzwwBg1alRUV1e3qL4//elPMXfu3Fi1alVs2LAhdttttxg2bFiMGzeuxXU15fXXX4+nnnoqli1bFjU1NbHnnnvGuHHjYp999mm319jR9ttvv9zjlStXlqgllNLWrVtjwYIF8fzzz8eaNWvivffei169ekX//v1j2LBhMWLEiBgyZEir63/ttdfimWeeiT//+c+xdevWGDJkSIwbNy6GDh3a5ra/8cYb8eSTT8bKlSvjrbfeih49esTuu+8eBx10UHz4wx+O7t27t7jO+fPnx8KFC2PVqlWxZcuW2GOPPWLfffeNMWPGtKq+xrz00kvx3HPPxbJly6KqqioGDRoUxx9/fAwaNKjdXqNTy8rY9ddfn0VE4W+7+++/PzvssMNy/xcRWb9+/XLLP/3009mXvvSlbMSIEfXK1v0bM2ZM9utf/7rZNk2bNi233OLFi5ss/4Mf/CBXvm/fvtmWLVuaXOayyy4rlB88eHCzbWqr2bNn59o4e/bsRsteeOGFhXLDhg0rPH/fffdlBx98cIPrtrKyMrvwwguzFStWNNuWJUuW5JadOnVq4fnTTjstq6qqavA1DjvssOx3v/tdG9cEqXnzzTezBx54IPvJT36S3XTTTdm3vvWt7I477sgef/zxbP369S2u749//GN27733Zt/73veym266Kbv99tuzBx98sFV1NeW1117L/uM//iP7zne+k/3Lv/xLdvfdd2evvvpqu75GR6m7v7j++utL3SQSVVNTk/3qV7/KjjrqqKyysrLR3+devXplJ554YjZ9+vQm69u6dWv2ox/9KNt3330brau6ujo799xzm/3t3m7q1Km55ZcsWZJlWZYtWLAg+7u/+7usoqKiwdc59thjs2effbbRet9+++2sV69ehfJnnXVW0ettu1tvvTX3mrNmzWpxHQ25/PLLc/X+53/+Z7vUSxrWrl2b/b//9/+y3Xffvdm+81577ZVdfvnl2apVq+rV01jfct68ednEiRMb3HYqKiqyCRMmZAsWLGhxuzdv3pzdfvvtjfZFt//17t07O+uss7JHHnmk2TrXr1+f3XTTTdngwYMbra9v377ZZZddVlQfN8sazzZz5szJjj766EZf5yMf+Uj2yiuvNFrvokWLcuW/+MUvFtWe2r74xS/m6njppZdaXEepJRdsr7zyykY/9NrB9u233252g2zob8qUKdmmTZsabdOKFSty5X/84x83+R5OP/30eq/x+OOPN7nM/vvvXyh7/vnnF7/CWqktwbampib7zGc+U9S63XfffbPXX3+9ybY0FGwfffTRbJdddmm2/oqKiuwb3/hGO68dyo3OcGk7w4It7eGNN97Ixo4d26Lf57oHr2tbsWJFgwe8G/vr0aNH4cBpUxralu++++7cdtjY30477ZQ9+OCDjdZ97rnn5trz5ptvtmgdjh49urD8XnvtlW3btq1Fyzdm3Lhxuffx1FNPtUu9lL8//vGP2d57793ivvPvf//7enU11Le89957i9p2unfvnt19991Ft/ull17KDjjggBa1+dBDD212XXzgAx8our4+ffpkM2fObLatDWWbb37zm1m3bt2afY3ddtste+655xqte8yYMYWyAwcObPZEWm1btmzJ9txzz8LyY8eOLXrZcpLUpcg333xzfP/734+IiD59+sTkyZNjv/32i27dusVrr70Wv//97xtcrrKyMg466KA46KCDYsiQIdGnT5/YunVrrFy5Mp555pmYP39+oexdd90VvXv3jltuuaXBuvbcc884+OCD4/nnn4+IiIcffjg+9alPNVh227ZtMWfOnHrPP/zwwzF27NgGl1m6dGm8/PLLhceTJ09usFy5+OpXvxq33nprRLy/biZPnhzDhg2LrVu3xsKFC+Ohhx6KrVu3RkTE4sWL46KLLopHHnkkKioqiqp/2bJl8cUvfjHefvvtiIg4/PDDY8yYMdGvX79YtmxZzJw5s3AvYJZlce2118bOO+8cn/3sZzvg3VJqK1asiLPOOiueeOKJZstu3LgxZs2aFb///e/jzDPPbLDMypUr4+STT465c+c2WdeGDRviF7/4RUyfPj1+/OMfx0UXXdTitt9zzz3xqU99qjBXZEMee+yxGDduXNx///3xd3/3d/X+v3///nHGGWfEL37xi4iIeOCBB+Ktt95q0aX+U6dOLfx7r732avB1oCO9+uqrcdxxx8Xy5ctzz++3335x7LHHxsCBA6OioiJWrVoVzz33XMybNy+2bdvWaH1vvvlmjB07Nl599dXCcxUVFTF27Ng4/PDDo3fv3rF06dKYMWNGvPnmmxERsXnz5rj44otjw4YNcdlllxXd9ocffjguu+yy2Lp1a+y0004xceLEOOCAA6JXr16xePHimDFjRqxduzYiItavXx8f//jH48UXX2zwdqeLL764sC1v3rw57r333rjyyiuLasfChQvj2WefLTy+8MILo7Ky7RNdLFmyJB5//PHC4/79+8eoUaPaXC/lb9OmTXHqqafG0qVLC8/17t07jjvuuPjgBz8Y/fr1i82bN8fbb78dixYtinnz5sW6deuKrv/ZZ5+Na6+9NjZt2hSVlZVx7LHHxujRo6O6ujpeffXVmDlzZmHb2bJlS1x00UXRu3fvOOOMM5qs96mnnoq///u/j7/+9a+550eOHBljxoyJPfbYI7Zu3RorVqyIuXPnxvPPP9/sFJcvv/xyHHPMMbFmzZrCc1VVVTFhwoQYOXJk9OzZMxYvXhwzZ84sDLT2zjvvxKmnnhr/+Z//GaeeemrR62Xq1KlxzTXXRMT729ukSZNi3333jaqqqli0aFHMmjUrNmzYEBERa9asiXPOOSfmzZvX4AjnF198cSELrVixImbNmhWnnHJKUe2YOXNm7raDiy++uOj3UFZKnaybUveoxvajGVdccUW2du3aeuVrn2n961//mk2aNCmbNm1as0dBFyxYUO/I8ZNPPtlo+c997nOFcgMGDMhqamoaLPfkk0/Wa3v8/2dlGnPnnXfm2vHnP/+5yba3h9aese3evXtWUVGRdevWLbv55psbPNO9YMGCbOjQobn6H3rooUbrr3vGtmfPnoWj0XPmzKlXfvPmzdlXvvKVesssWrSoVeuC8rV48eJsyJAh9Y5g7rffftnFF1+c/dM//VN27bXXZp/4xCeyww8/vLDNNXaWZ82aNfWOxlZUVGTHHHNM9rnPfS677rrrsvPPPz8bMGBAvde87bbbmmxr3bM8t99+e+Ey+p122ik75ZRTsi996UvZl7/85ezcc8/N+vXrV++obEOXdmVZlj344IO5srfeemvR63DBggW5Za+77rqil93OGVvaYv369dmHP/zh3Hfo4IMPbvJ3Z9WqVdn3v//97LDDDmvw/+teGXXQQQdlc+fOrVdu48aN2TXXXFPv96KpMyB1t+UePXpkEZGdd955DW6ja9asySZNmlTUdrZt27bc7+Po0aMbbUddV111Ve41Xn755aKXbcpFF12Uq3fKlCntUi/l72c/+1m9z76hvvZ2mzdvzh555JHs7LPPzp555pl6/1/3t2J7f27EiBHZ/Pnz65V/5513sk9+8pNF/xZm2fv7hr322iu3zLhx45q88mnp0qXZTTfdlJ144okN/v+WLVuyI444IlfnMccc0+BlwGvXrq23zey6665N9t3rZpvt+5QvfvGL2TvvvFOv/Ouvv54dcsgh9foUDVm7dm1WXV1dKHfmmWc22o66zjjjjMJyO+20U5OffTlLKthu/+A7wsaNG3OX9ZxzzjmNln3ggQdybWroBzTLsuzrX/96ocx5551X6Nh27969wS9vluUvTTrggAPa5b01p7XBdvvfz3/+8ybrf/zxx3PlL7jggkbL1g2224NJc9f5117XEZGdeuqpTZYnLTrDf1PqzrBgS1v88z//c+77M3bs2KI7UA0dRH700Udz9e2zzz7ZypUrm6znhhtuyC0zceLERsvW3ZYjIvvkJz/ZZP1vv/127v7Evffeu9GyX/7yl3N1F3Nv4ZYtW7I99tijsExTB8tbou5Bsx49erRbYKb8nX/++YXP/oMf/GCbL22v+1sR8f4tbM1tn5/4xCdyy3zmM59ptOwll1ySK3vmmWdmmzdvLqp9jZ2Uuuuuu3J1Hnnkkdl7773XZF0XX3xx0QeEGso2N954Y5P1L168uHBgICKy4447rtGy5513Xm4bXrNmTZN1Z1mWrV69OuvevXthuR1xG2RHSSrYDh8+PNu4cWOHvd6vfvWrXJhq7Eu/bt263CBG3/rWtxosN378+EKZ6dOn5+5b+Z//+Z965WtqanLXt1955ZXt+v4a05Zge/rppxf1GrWPfu2///6Nlmso2H7ve99rtv6tW7dmhx56aGGZbt26ZUuXLi2qbZQ/neG8UnaGBVta67333st222233O/ssmXL2lRn3QNUxdzjtnXr1mzUqFG55RYuXNhg2brb8sCBA7MNGzY0+xpXX311brnly5c3WO6VV17Jlbvqqquarfv+++/PLXPXXXc1u0xzli9fnut/2La7nhNOOKHw2Z999tltrq+hYHv//fc3u9y6deuyQYMG5fYTDQXLZcuWFQ4abw/N69ata3O7ax9E79atW6P7htreeeed3ABTvXr1ylavXt1g2brZZtSoUY3mjdo+9rGPFZaprq7Otm7d2mC5Rx55JFf/Lbfc0mzd3/ve93LLPProo80uU67afkPGDjRlypTo2bNnh9U/cuTIwr/Xrl0bixYtarBcnz594sgjjyw8fvjhh+uVWb9+feE698rKypg4cWLuftmGlnn++edz17dPmjSp5W9iB7viiiuKKnfccccV/v3KK6/Eli1bilpup512iksuuaTZct26dcvdm7Rt27a4//77i3oNytv69etz97z369cvfvnLX0bfvn2LWr6h+7n/7d/+Lff4tttuiz322KPJeq677rrcvWaPPvpo4V775gwcOLDea9bVv3//3L27S5cujb/85S8Nlq17j2/t+2Yb85vf/CY3N22y98+QrIceeih3z9onP/nJ2GuvvVpd3+bNm2PmzJmFxwceeGCceOKJzS7XrVu3+MIXvpB77te//nVRr3nJJZc0eG9bXbV/8yKi0f7Evvvumys7bdq0wrgUjfnpT39a+PfOO+8cH/vYx5ptT1M2bNgQZ5xxRq7/cfTRR8d1113XpnpJS+/evQv/nj9/ftTU1LRr/cOHD4+PfOQjzZbr06dPTJkypfB47dq18cgjj9QrN3369Ni8eXPh8dVXXx19+vRpUxuXLl0azz33XOHxCSecEAcffHCzy/Xu3Tt3r/7GjRvjf//3f4t6zcsvv7yocWdq7yc2bNgQr732WoPlJkyYEMOHDy88rr2/aEztMsOHD4/x48c3u0y5SirYtnZFv/XWW/HjH/84zjvvvDj00ENj0KBBsfPOO0dVVVXub8SIEbnl/vznPzdaZ+2Q+n//93+xadOm3P8/9thjhecOP/zw6N+/f26Zhx56qF6dtcNut27dYsKECS17oztYt27d4phjjimqbO2NLMuyogccmDBhQm5n25S6O8w//OEPRS1HedMZrq8cOsPQUnUHUzz33HPbVN+8efNyv72nnXZa0cuedtppucGWihmQLqL+NtqY2r95EVFvYJvaanfiV61aFb/5zW8aLbt69erc/3/sYx8r+jeyIdu2bYtzzz03nnrqqcJzQ4cOjfvuu69d5+ak/NU+YfPSSy/FJz7xicLAne3h5JNPLnrg0GL6c7X3JxUVFXHOOee0qX0RUW8Q2pbsU+oOUlmq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cMIJhcf33ntvYcCX2qOa7rLLLi0+w/roo4/G2Wefnetr3HzzzfHpT3+6bY2mS9prr73immuuyT3XXHCdMWNG0QOHFtOfq7s/+cUvflFU3U2pux9oyT7lv/7rv5qsqxTGjBmT66fU7h/U/veBBx4YRx999A5sWcfplMG29iUSq1evzh1BaczMmTNj7ty5LX6t2iH1lVdeyY0wOGnSpAZDde1lfvvb38asWbMKj3fdddcWjdLa2b333ntx5513NluupqYmvv/97xceV1ZWtmgaF8qXznDTOrIzDO1p8uTJuVFDb7/99ibni29O9+7d46STTio8XrRoUe73tDE1NTXx3e9+N/dcuWwbtQ8+rVmzJh544IFYuXJl7n2de+65Rc2Lvd1TTz0Vp512Wm6as6985Stx9dVXt0+j6ZI+8IEP5B43NwPJkiVL4oEHHmi23nfffTfXl+7Xr1+DJ3w++tGPRo8ePQqPv/3tb7d53IuhQ4fm+uAPPvhgbmaGxrz33nvxox/9qPC4V69eceKJJ7apLe2l9j5lwYIF8eyzz8bcuXNj4cKFDZZJXacMtiNGjCj8e8uWLU1OgxER8frrr8cnP/nJVr1W3Y3tlltuKfy7sUuKhwwZUjiCsm7dulznc8KECbmzL0Rcf/31ubNkDbn55ptzRwtPPvnk2HvvvTu4ZewIOsPN64jOMLS36urq+NznPld4vG7dujj77LOL7ow2dLbns5/9bO7x5Zdf3ujo4NvddNNNuQPZkydPzvUbSum0007L3eIwderUuOeee1p9yeALL7wQJ510Um5sgKuuuipuuOGG9mkwncbTTz/dovK1p6iMqD8Pe0M+//nPN7t9fulLX4q//OUvhccXXHBB7LTTTvXKDRo0KC688MLC49dffz0uuuiiBqe1aUhjZ49r71O2bdsWl1xySbMnyK666qpcv+S8885rl3l128P555+fm01i6tSpudzRrVu3OP/880vRtI6RlbHrr78+i4jCX7HeeOONrEePHoXlqqurs+nTpzdY9sEHH8z23nvvLCKynXfeOfd6U6dOLer1PvCBD+SW2/73+uuvN7rMlVde2eAyP/zhD4t+n+1l9uzZuTbMnj270bIXXnhhodywYcOKfo2pU6fmXmPJkiUNlluyZEmuXM+ePbOIyIYOHZr99re/rVd+y5Yt2Q033JBVVFTklnnxxReLbhvl78Ybb8x9L8aOHZutW7euqGVramrqPVf3O7/PPvtkq1atarKer3/967llJk+e3GjZYr/vddX9/he7D9q4cWO2yy67FJY75ZRTsn/5l3/J1fX0008XVVdz6q6766+/vl3qpWvYsGFDNmrUqNx3aOTIkdmcOXMaXebNN9/Mbrvttuywww5r8P/POOOMXH0jRozI5s2bV6/cpk2bsuuuu67eb8xzzz3X6Gvv6G05y7LsiiuuKCxXVVWV7bPPPoXHBx98cNH1LFmyJBs8eHCuHZdeemnRy9O1DBs2LDvkkEOyf/u3f8uWLVvWaLlt27ZlP/7xj7OqqqrC92ro0KHZtm3bcuXq/lZs78+NHDkyW7BgQb1633333ezTn/50bpnddtutyd/mNWvWZEOHDs0tc+yxxza4/W+3fPny7Jvf/GZ20kknNfj/W7ZsyY444oh6db766qv1yq5bty675JJLcmV33XXX7M9//nOjr9/abNOSvnpdJ598cmG5AQMGZLvuumuuv9CZVDUWeFM2cODAuOKKKwpnVzZs2BBnnXVWjBo1Ko477rjo169frFmzJn7729/GCy+8EBHvH7H413/917j00ktb/HqTJ0/OTS8UEbH//vs3ecZw8uTJuUtnaz/P31x77bVxyy23xLJly+L444+PI488Mo4++ujo27dvLF++PGbMmFFvNOubb745DjzwwBK1mI7whS98Ie67777C/bBPPPFEHHPMMXHrrbfG8ccf3+Ayb731Vvzyl7+MO++8s97AcOPHj48zzjijcE/MkiVLYsKECfHzn/88PvzhD+fKbt68Ob72ta/FjTfeWHiuZ8+euTkgS61nz57x8Y9/PH7wgx9ERMSsWbMK+7aIiIMPPjgOP/zwUjUPCnr16hX33XdfHHfccYWRTBcuXBjjx4+P/fffP4499tgYOHBgVFRUxOrVq2P+/Pnx7LPPxpYtW6Jfv34N1nn77bfH/Pnz49VXX42I989Sjh49OsaNGxeHHXZY9O7dO5YuXRozZszI3XMeEfHd7363wbEwSuniiy8ubMtbt26NJUuW5P6vWD/72c9yZ74iIu6444644447WtSer3zlK/GVr3ylRcuQpgULFsRnP/vZ+NznPhf77rtvjB49OoYMGRL9+vWLTZs2xdKlS2POnDn1RiG+5ZZbmr3a8Bvf+EZce+21sXDhwvjwhz8cxx13XIwePTqqq6tjyZIlMWPGjNwYOZWVlfGTn/wkN0hrXQMGDIj77rsvTjjhhFi7dm1ERDz22GMxatSoOOSQQ2LMmDGx++67x7Zt22LFihXx3HPPxfz586OmpqbR7b6qqiqmTZsWY8eOLewvHnvssfjgBz8YEydOjEMOOSR69OgRixcvjpkzZ+ZGb66qqoqf/vSnMWTIkCbXxY528cUXF+axrTvIVme6DDkiOucZ2yx7/8jspEmTGjwrWveve/fu2d13393qI6y//OUv69V52WWXNbnM2rVrs27duuWW2XvvvVv0HttLOZ+xnTp1avbII49k/fv3b/ZzrKioyG688caWvXmSsXjx4mzIkCH1Pvf9998/mzJlSnbttddm1113XfapT30qO+qoo7Lu3btnEZH169evwfrWrFlT72qLioqK7Nhjj80+//nPZ1/+8pezCy64INttt93qveZtt93WZFtLcZbnmWeeaXTb+M53vlN0PdvdcMMNWbdu3er9VVZW1ltnDZXbd999W/yadB3Lly+vd1akub/GtuUse/9KrdGjRxddV/fu3bM777yz2XaWYlvOsiwbOXJkvTZXVVVlK1euLLqOun2o1v65KqNrGDZsWIu/Gz169MjuuOOOButrqG85bdq0wpnbpv6qqqqyn/3sZ0W3/cUXX8z222+/FrX90EMPbbLOl156KXe1RHN/ffr0yWbMmNFsW0txxnbTpk3ZgAED6rV5t912yzZv3lx0PSnotDdz9ujRI2bNmhU33HBD9O/fv8Ey3bt3j4985CPx1FNPten68oYGiWruzGvfvn3jyCOPbNEyXdXEiRPjmWeeiVNOOSV3n0Bto0ePjjlz5sS11167g1vHjvKBD3wgnnrqqTjiiCNyz7/88stx1113xTe+8Y248cYb4yc/+Un84Q9/aPY+mwEDBsTjjz8eo0ePLjyXZVk89thj8b3vfS++/vWvx9133507w9O9e/e4884747LLLmvfN9cODjvssNwI0ttVVVW1ajqPmpqa2LZtW72/2oNnRby/zhoq19ZpmejcBg8eHE8++WTcc8899a6SqKu6ujpOPfXUmDZtWqNlBg4cGH/4wx/ihz/8Yey7776NluvVq1ecc845sWjRopgyZUprm9/hGjqLcvLJJ+fGG4D2dM8998RVV10VI0aMaHY2kd69e8cFF1wQL7zwQlxyySVFv8bHP/7xePzxx+P4449v8DUqKipi/PjxMXfu3BbNuX7ggQfGCy+8ELfeemtubveG9OvXL84999wGr5qs7UMf+lC88MILceONN8bgwYMbLdenT5/49Kc/HX/6059y43eUkx49esQ//uM/1nv+H//xH6N79+4laFHHqciyIsfeTtiGDRvi8ccfj0WLFsU777wTAwYMiMGDB8cxxxwTu+66a6mbRy2vvfZa7LPPPoXHU6dOzc3TuWLFinjiiSdi+fLlsX79+hg0aFAcddRR9aZwofOqqamJe++9N77zne80Ob1AdXV1TJ48OS699NI4+eSTGy23devWuOOOO+Lb3/52LF68uMEyvXr1itNPPz2+/vWvN9lp3u6nP/1prmO6ZMmSogbWaO7735zvfve78YUvfCH33GmnnRb3339/0XVs99WvfrVNA8wMGzas2XkNYbs33ngjnnjiiVi5cmW8/fbb0bNnz9htt93igAMOiFGjRkXPnj1bVN8f//jHmDt3bqxatSo2bNgQu+22WwwbNiyOPfbYqK6u7qB3AZ3DX//611i4cGG8+uqrsWbNmli/fn1UV1fHgAED4qCDDopDDz202cEI58yZExMmTCg8nj17dm6WgyVLlsTTTz8dy5cvj23btsXgwYNj3Lhx7TLw55IlS+Kpp56KVatWxdq1a6O6ujr23HPPOOigg+KQQw6JqqqW34n53HPPxYIFC2L16tWxZcuW2H333WO//faLsWPHdrpwmLIuEWxJR1s79nQtOsMAUH6aC7bQETrl4FFA1zBo0KA466yz2q2+D33oQ87+AwAkqNPeYwsAAEDXINgCAACQNMEWAACApAm2iZg0aVJUVVW129/Xvva1Ur8lAACAdmHwqERsnxuyvdSdixIAACBVgi1lZfjw4WEGKgCAdI0fP15/jh3OPLYAAAAkzT22AAAAJE2wBQAAIGmCLQAAAEkTbAEAAEiaYAsAAEDSBFsAAACSJtgCAACQNMEWAACApAm2AAAAJE2wBQAAIGmCLQAAAEkTbAEAAEiaYAsAAEDSBFsAAACSJtgCAACQtKpiC1ZWysBQjJqamlI3oUm2ZShOOW/LtmMoTjlvxxG2ZShWMduyrQkAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAk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aYHUhhzvCM2tA8OVsyPZJkvDegegvfhN0b9uL75JAAAAJE2wBQAAIGmCLQAAAEkTbAEAAEiaYAsAAEDSBFsAAACS1imn+zFseOlY9wAAnY8+XulY98WxlgAAAEiaYAsAAEDSBFsAAACSJtgCAACQNMEWAACApAm2AAAAJE2wBQAAIGmCLQAAAEkTbAEAAEiaYAsAAEDSBFsAAACSJtgCAACQNMEWAACApAm2AAAAJK0iy7Ks1I0AAACA1nLGFgAAgKQJtgAAACRNsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAkibYAgAAkDTBFgAAgKQJtgAAACRNsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAkibYAgAAkDTBFgAAgKQJtgAAACRNsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAkibYAgAAkDTBFgAAgKQJtgAAACRNsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAkibYAgAAkDTBFgAAgKQJtgAAACRNsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAkibYAgAAkDTBFgAAgKQJtgAAACStqtQNqKyUrelcampqSt2EDmFbpatJdVu2rcLfpLodt5X9AJ1NMduybz0AAABJE2wBAABImmALAABA0gRbAAAAkibYAgAAkLSSj4oMALSMEU8BIM8vIwAAAEkTbAEAAEiaYAsAAEDSBFsAAACSJtgCAACQNMEWAACApJnuB7oY04QAANDZ6OECAACQNMEWAACApAm2AAAAJE2wBQAAIGmCLQAAAEkTbAEAAEiaYAsAAEDSip7H1tyXlEpNTU2pmwAA0O70rymVzti/tjUBAACQNMEWAACApAm2AAAAJE2wBQAAIGmCLQAAAEkTbAEAAEha0dP9AEBH6oxTDwAAO4YztgAAACRNsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAkma6n06sI6bOqKx0LAQAgK5J/7p8WYsAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJJmuh+AhDU17UBq0weUW3s7YkoHAKBjlFcvAgAAAFpIsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAkibYAgAAkLROOY9tKeYeLLf5FzuT1NatuS8BgM5G/7pzSW3dFvP9S+sdAQAAQB2CLQAAAEkTbAEAAEiaYAsAAEDSBFsAAACSJtgCAACQtE453Q/QNbR26oHUhrgHAKBpencAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNKqSt0AgNaqrHRszjoAAHDGFgAAgMQJtgAAACRNsAUAACBpgi0AAABJE2wBAABImmALAABA0gRbAAAAktYp57E1r+P7rAcAANqDfuX7rIfy5ZMBAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNKqii1YU1PTqheorOwa2bm166ctusq6bU5HrHvrFgDoaPrXTdO/Lp0U+9c+OQAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASSt6uh+gc2hq+HZD3DfP1Ayl4XsLADRFbwAAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNJM9wPQAqaWAQAoP3poAAAAJE2wBQAAIGmCLQAAAEkTbAEAAEiaYAsAAEDSBFsAAACSZrqfdmIKEICOYx8L0PXY99MSvi0AAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA089iSPHOcAQBA+0mxf51eiwEAAKAWwRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaVWlbgCtV1NTU+om1FNZ6VgJAABp0r9Ol7UEAABA0gRbAAAAkibYAgAAkDTBFgAAgKQJtgAAACRNsAUAACBpgi0AAABJM48tQJnriDn1zIkHAHQmejYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJJmuh+AMmdqHgCApuktAQAAkDTBFgAAgKQJtgAAACRNsAUAACBpgi0AAABJE2wBAABImul+EmYKEAAAaD/61+nyyQEAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASRNsAQAASJpgCwAAQNIEWwAAAJIm2AIAAJA0wRYAAICkCbYAAAAkTbAFAAAgaYItAAAASavIsiwrdSMAAACgtZyxBQAAIGmCLQAAAEkTbAEAAEiaYAsAAEDSBFsAAACSJtgCAACQNMEWAACApAm2AAAAJE2wBQAAIGn/H/zdu+xxEf6KAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 1200x900 with 12 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# visualization\n",
    "\n",
    "from typing import List\n",
    "import PIL.Image as PImage\n",
    "import matplotlib.pyplot as plt\n",
    "from torchvision import transforms\n",
    "\n",
    "raw_inps, conv1s, conv2s, spconvs = [], [], [], []\n",
    "for i in range(N):\n",
    "    raw_inps.append(raw_inp[i].repeat(3, 1, 1).clamp(1, 255))\n",
    "    conv1s.append(conv1[i].repeat(3, 1, 1).clamp(1, 255))\n",
    "    conv2s.append(conv2[i].repeat(3, 1, 1).clamp(1, 255))\n",
    "    spconvs.append(spconv[i].repeat(3, 1, 1).clamp(1, 255))\n",
    "\n",
    "n_rows, n_cols = N, 4\n",
    "plt.figure(figsize=(n_cols * 3, n_rows * 3))\n",
    "\n",
    "tensor2pil = transforms.ToPILImage()\n",
    "for col, (title, chws) in enumerate([('raw_inp', raw_inps), ('conv1', conv1s), ('conv2', conv2s), ('spconv', spconvs)]):\n",
    "    p_imgs: List[PImage.Image] = [tensor2pil(t).convert('RGB') for t in chws]\n",
    "    for row, im in enumerate(p_imgs):\n",
    "        plt.subplot(n_rows, n_cols, 1 + row * n_cols + col)\n",
    "        plt.xticks([]), plt.yticks([]), plt.axis('off')\n",
    "        plt.imshow(im)\n",
    "        if row == 0:\n",
    "            plt.title(title, size=28, pad=18)\n",
    "plt.show()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
